package service

import (
	"database/sql"
	"errors"
	cDto "ssadmin/common/query"
	"ssadmin/common/utils"
	"ssadmin/internal/admin/models"
	"ssadmin/internal/admin/models/command"
	"ssadmin/internal/admin/models/query"
	"strings"

	"gitee.com/sansaniot/ssiot-core/httpmvc/service"
	"gorm.io/gorm"
)

type UserWX struct {
	service.Service
}

const (
	// MP_APPID appId
	//MP_APPID = "wx5d5899cc9a4f01fb"

	// MP_SECRET secret
	//MP_SECRET = "c048a3cfddd31e23d0bce2193638c309"

	// MP_API_LOGIN 微信登录，code换取openid
	MP_API_LOGIN = "https://api.weixin.qq.com/sns/jscode2session?appid=${appId}&secret=${secret}&js_code=${code}&grant_type=authorization_code"

	// MP_API_TOKEN 获取access_token
	MP_API_TOKEN = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appId}&secret=${secret}"

	// MP_API_PHONE 获取微信数据
	MP_API_PHONE = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=${token}"
)

// GetOpenid code换取openid
func (e *UserWX) CodeLogin(req *command.UserWeixin, userInfo *models.User) error {
	openid := e._getWeixinOpenid(req.Code, req.MpAppId) //step-2 通过openid查用户
	if err := e._openidLogin(openid, userInfo); err != nil {
		return err
	}
	userInfo.AfterSet()
	userInfo.CreateTime = userInfo.CreateTimeDts.Format(utils.TIME_FMT_FULL)
	if strings.Contains(userInfo.CreateTime, utils.TIME_NIL) {
		userInfo.CreateTime = ""
	}
	return nil
}

//绑定微信用户
func (e *UserWX) Bind(c *command.UserWeixin, userInfo *models.User) error {
	openid := e._getWeixinOpenid(c.Code, c.MpAppId)
	//参数校验
	if len(openid) == 0 || len(c.Username) == 0 || len(c.Password) == 0 {
		return errors.New("参数非法")
	}

	dbModel := models.User{}
	//step-1 通过username+pwd查用户
	targetUser := models.User{}
	if err := dbModel.FindOne(e.Orm, &targetUser, cDto.MakeCondition(query.UserQuery{UsernameEq: c.Username})); err != nil {
		return err
	}
	//先解密
	decodePwd, err := utils.AesDecrypt(c.Password, c.AesKey)
	if err != nil {
		return err
	}
	//获取MD5密码
	inputPwd := utils.Md5Pwd(decodePwd, c.Username+decodePwd)
	//输入密码和数据库密码比对
	if inputPwd != targetUser.Password {
		return errors.New("用户名或密码错误")
	}

	//step-3 判断step-1与step-2用户是否为同一用户
	txErr := e.Orm.Transaction(func(tx *gorm.DB) error {
		//清空所有旧的openid缓存(可能错误存在一个openid 对应 多个用户)
		tx.Table("t_user").Where("open_id = ?", openid).Update("open_id", sql.NullString{})
		//openid绑定到的用户
		targetUser.OpenId = openid
		if err := dbModel.Mod(tx, &targetUser, cDto.MakeCondition(query.UserQuery{UserId: targetUser.UserId})); err != nil {
			return err
		}
		targetUser.AfterSet()
		targetUser.CreateTime = targetUser.CreateTimeDts.Format(utils.TIME_FMT_FULL)
		if strings.Contains(targetUser.CreateTime, utils.TIME_NIL) {
			targetUser.CreateTime = ""
		}
		*userInfo = targetUser
		return nil
	})
	if txErr != nil {
		return txErr
	}
	return nil
}

// 手机号登录
func (e *UserWX) PhoneLogin(req *command.UserWeixin, userInfo *models.User) error {
	if err := e._phoneLogin(req.Phone, userInfo); err != nil {
		return err
	}
	userInfo.AfterSet()
	userInfo.CreateTime = userInfo.CreateTimeDts.Format(utils.TIME_FMT_FULL)
	if strings.Contains(userInfo.CreateTime, utils.TIME_NIL) {
		userInfo.CreateTime = ""
	}
	return nil
}

// GetOpenid code换取openid
func (e *UserWX) GetOpenid(code string, appId string) string {
	//通过code和appId获取当前对应的openId
	openid := e._getWeixinOpenid(code, appId)
	return openid
}

//openid获取平台用户
func (e *UserWX) _openidLogin(openid string, userInfo *models.User) error {
	if len(openid) == 0 {
		return nil
	}
	um := models.User{}
	if err := um.FindOne(e.Orm, userInfo, cDto.MakeCondition(query.UserQuery{Openid: openid})); err != nil {
		return err
	}
	return nil
}

//手机号登录
func (e *UserWX) _phoneLogin(phone string, userInfo *models.User) error {
	if len(phone) == 0 {
		return nil
	}
	um := models.User{}
	if err := um.FindOne(e.Orm, userInfo, cDto.MakeCondition(query.UserQuery{Mobile: phone})); err != nil {
		return err
	}
	return nil
}

//获取openid
func (e *UserWX) _getWeixinOpenid(code string, appId string) string {
	url := MP_API_LOGIN
	//url := MP_API_TOKEN
	url = strings.Replace(url, "${appId}", appId, 1)
	url = strings.Replace(url, "${secret}", getSecret(appId), 1)
	url = strings.Replace(url, "${code}", code, 1)

	//code换取openid
	res := make(map[string]interface{})
	utils.HttpGet(url, &res)
	var openid string
	if v, ok := res["openid"]; ok {
		openid = v.(string)
	}
	return openid
}

func getSecret(appId string) string {
	if appId == "wxac81fa6195992f8f" {
		return "031a19d53bbdc88c9388f30e2d31a4cc"
	} else if appId == "wx5d5899cc9a4f01fb" {
		return "c048a3cfddd31e23d0bce2193638c309"
	}
	return ""
}
